package com.edu.labmanager.config;



import com.edu.labmanager.service.impl.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableMethodSecurity
public class MySecurityConfig {

    //将密码加密器配置到容器中
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService(){
        return new UserServiceImpl();
    }



    //DaoAuthenticationProvider 会调用配置好的 UserDetailsService 接口实现类的 loadUserByUsername 方法，
    // 根据用户输入的用户名从数据源（如数据库）中加载用户的详细信息，包括用户名、密码、权限等，这些信息会被封装成一个 UserDetails 对象。
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(passwordEncoder());
        return provider;

    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
        //配置用户认证(登录相关配置)
        security.formLogin(configurer -> {
            configurer
                    //配置登录页面地址
                    .loginPage("/user/login")
                    //配置登录请求处理地址（Post）
                    // 用户在登录页面填写用户名和密码后，表单数据会以 POST 请求的方式发送到 /user/login。
                    // Spring Security 会拦截这个请求，从请求中提取用户名和密码信息。
                    // 注意:这里配置的地址要和页面一致，否则会导致登录失败。
                    .loginProcessingUrl("/user/login")
                    //配置登录请求的用户名和密码参数
                    .usernameParameter("username")
                    .passwordParameter("password")
                    //配置登录成功后默认跳转的页面
                    .defaultSuccessUrl("/user/index")
                    //配置登录失败后默认重定向的页面
                    .failureForwardUrl("/user/loginFail");
        });
        //配置用户退出
        security.logout(configurer -> {
            //配置退出请求处理地址
            configurer.logoutUrl("/user/logout");
        });
        //配置用户权限
        security.authorizeHttpRequests(registry -> {
            registry
                    //不需要认证的路径
                    .requestMatchers(
                            "/user/login",
                            "/user/register",
                            "/user/loginFail").permitAll()
//                    //为系统资源配置访问权限
//                    .requestMatchers("/order/manage").hasAuthority("订单管理")
//                    .requestMatchers("/shop/manage").hasAuthority("店铺管理")
//                    .requestMatchers("/user/manage").hasAuthority("系统用户管理")
                    //为系统资源配置角色访问
//                    .requestMatchers("/order/manage").hasAnyRole("common","vip","manager")
//                    .requestMatchers("/shop/manage").hasAnyRole("vip","manager")
//                    .requestMatchers("/user/manage").hasRole("manager")
                    //除了上面的路径，其他请求都需要认证登录
                    .anyRequest().authenticated();
        });

        //配置无权限跳转
        security.exceptionHandling(configurer -> {
            configurer.accessDeniedPage("/user/noauth");
        });

        //记住我功能配置
        security.rememberMe(configurer -> {
            configurer
                    .userDetailsService(userDetailsService())
                    //修改复选框name值
                    .rememberMeParameter("rememberMe")
                    //设置cookie的有效时间
                    .tokenValiditySeconds(3600);
        });

        //配置CSRF防御
        security.csrf(configurer -> {
            configurer.disable();
        });
        return security.build();
    }

}